package cn.zebra.dev.admin.module.login;

import cn.zebra.dev.admin.module.security.entity.AdminDetailsEntity;
import cn.zebra.dev.base.module.admin.entity.BaseAdmin;
import cn.zebra.dev.base.module.admin.service.BaseAdminService;
import cn.zebra.dev.common.constant.SysConstant;
import cn.zebra.dev.common.utils.SecurityUtils;
import cn.zebra.dev.jwt.utils.JwtTokenUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

/**
 * @author runnable@sina.cn
 */
@Service
public class LoginService {

    @Autowired
    private BaseAdminService adminService;

    @Autowired
    private StringRedisTemplate redisTemplate;


    /**
     * Admin登录 成功返回token
     *
     * @param account  后台用户账号
     * @param password 登录密码
     * @return token
     */
    public String login(String account, String password) {
        BaseAdmin admin = adminService.findAdminByAccount(account);
        if (admin == null) {
            throw new RuntimeException("用户名或密码不正确!");
        }
        String salt = admin.getSalt();
        if (!SecurityUtils.getMd5(salt + admin.getLastLoginTime() + password).equals(admin.getPassword())) {
            throw new RuntimeException("用户名或密码不正确!");
        }
        long lastTime = System.currentTimeMillis();
        admin.setLastLoginTime(lastTime);

        if (!adminService.resetPassword(admin.getId(), salt, password)) {
            throw new RuntimeException("登陆失败!无法校验用户信息!");
        }
        AdminDetailsEntity userDetails = new AdminDetailsEntity(admin);
        return initToken(account, userDetails);
    }

    /**
     * 根据用户名和用户信息初始化token
     *
     * @param userName    用户名
     * @param userDetails 用户信息
     * @return token
     */
    private String initToken(String userName, UserDetails userDetails) {
        String token = JwtTokenUtil.validateTokenExist(userName, userDetails, redisTemplate.opsForValue());
        setTokenAndUserDetails(userName, userDetails, token);
        return token;
    }

    /**
     * 设置用户token存放redis和注入Security用户信息
     *
     * @param userName    用户名
     * @param userDetails 用户详情
     * @param token       token
     */
    @Async
    void setTokenAndUserDetails(String userName, UserDetails userDetails, String token) {
        UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authentication);
        //缓存token
        redisTemplate.opsForValue().set(SysConstant.USER_TOKEN + userName, token, 7, TimeUnit.DAYS);
    }

    /**
     * 退出登录
     *
     * @param userName 用户名
     */
    @Async
    public void logout(String userName) {
        RedisOperations<String, String> operations = redisTemplate.opsForValue().getOperations();
        operations.delete(SysConstant.USER_TOKEN + userName);
        operations.delete(SysConstant.SECURITY_ADMIN_ACCOUNT + userName);
        SecurityContextHolder.clearContext();
    }
}
